package com.dzx.currentency.lock;

import lombok.extern.slf4j.Slf4j;
import org.omg.CORBA.PUBLIC_MEMBER;

import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.*;

/**
 * @author DuanZhaoXu
 * @ClassName:
 * @Description:
 * @date 2018年11月20日 11:52:56
 */

/**
 * class Point {
 * *   private double x, y;
 * *   private final StampedLock sl = new StampedLock();
 * *
 * *   void move(double deltaX, double deltaY) { // an exclusively locked method
 * *     long stamp = sl.writeLock();
 * *     try {
 * *       x += deltaX;
 * *       y += deltaY;
 * *     } finally {
 * *       sl.unlockWrite(stamp);
 * *     }
 * *   }
 * *
 * *   double distanceFromOrigin() { // A read-only method
 * *     long stamp = sl.tryOptimisticRead();
 * *     double currentX = x, currentY = y;
 * *     if (!sl.validate(stamp)) {
 * *        stamp = sl.readLock();
 * *        try {
 * *          currentX = x;
 * *          currentY = y;
 * *        } finally {
 * *           sl.unlockRead(stamp);
 * *        }
 * *     }
 * *     return Math.sqrt(currentX * currentX + currentY * currentY);
 * *   }
 * *
 * *   void moveIfAtOrigin(double newX, double newY) { // upgrade
 * *     // Could instead start with optimistic, not read mode
 * *     long stamp = sl.readLock();
 * *     try {
 * *       while (x == 0.0 && y == 0.0) {
 * *         long ws = sl.tryConvertToWriteLock(stamp);
 * *         if (ws != 0L) {
 * *           stamp = ws;
 * *           x = newX;
 * *           y = newY;
 * *           break;
 * *         }
 * *         else {
 * *           sl.unlockRead(stamp);
 * *           stamp = sl.writeLock();
 * *         }
 * *       }
 * *     } finally {
 * *       sl.unlock(stamp);
 * *     }
 * *   }
 * * }}</pre>
 * *
 */
@Slf4j
public class LockExample1 {

    private static int clientTotal = 5000;
    private static int threadTotal = 200;
    private static int count = 0;


    //重入锁
    private final static Lock lock = new ReentrantLock();


    //重入读写锁
    private final static Map<Integer, Integer> map = new TreeMap<Integer, Integer>();
    private final static ReentrantReadWriteLock reenLock = new ReentrantReadWriteLock();
    private final static Lock readLock = reenLock.readLock();
    private final static Lock writeLock = reenLock.writeLock();

    //stamped锁
    private final static StampedLock stampedLock = new StampedLock();

    //condition
    private final  static  ReentrantLock  REENTRANT_LOCK = new ReentrantLock();
    private final static Condition  condition = REENTRANT_LOCK.newCondition();

    //重入读写锁的使用
    public Integer getValue(Integer key) {
        readLock.lock();
        Integer value = null;
        try {
            value = map.get(key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readLock.unlock();
        }
        return value;
    }

    //重入读写锁的使用
    public Set<Integer> getSet() {
        Set<Integer> set = null;
        readLock.lock();
        try {
            set = map.keySet();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readLock.unlock();
        }
        return set;
    }

    /**
     * 重入读写锁的使用
     * @param key
     * @param value
     * @return
     */
    public Integer put(Integer key, Integer value) {
        writeLock.lock();
        try {
            map.put(key, value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            writeLock.unlock();
        }
        return value;
    }

    /**
     * condition的使用
     */
    public  static  void  testCond(){
             new Thread(() -> {
                 try {
                     REENTRANT_LOCK.lock();
                     log.info("运动员获取锁");
                     condition.await();
                     log.info("运动员接收到信号，比赛开始~~~~");
                 }catch (Exception e){
                     e.printStackTrace();
                 }finally {
                     REENTRANT_LOCK.unlock();
                 }
             }).start();

             new Thread(() -> {
                 try {
                     REENTRANT_LOCK.lock();
                     log.info("裁判获取锁");
                     Thread.sleep(3000);
                     log.info("裁判发送信号");
                     condition.signalAll();
                 }catch (Exception e){
                     e.printStackTrace();
                 }finally {
                     REENTRANT_LOCK.unlock();
                 }
             }).start();
    }


    public static void main(String[] args) throws InterruptedException {
        ExecutorService service = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal; i++) {
            service.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
        countDownLatch.await();
        service.shutdown();
        log.info("count {}", count);
        testCond();
    }

    /**
     * stampedLock的使用方式
     */
    private static void add() {
        long stamp = stampedLock.writeLock();
        try {
            count++;
        } catch (Exception e) {
        } finally {
            stampedLock.unlock(stamp);
        }
    }
}
